package com.dream.banana.redis.client;

import org.redisson.client.RedisException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.JedisCommands;
import redis.clients.jedis.exceptions.JedisConnectionException;
import redis.clients.util.Pool;

import java.net.SocketTimeoutException;

/**
 * 躲了一辈子雨，雨会不会很难过。
 * </p>
 * Created by zhumenglong on 2017/5/29.
 */
public abstract class AbstractRedisClient implements IRedisClient {
    private static Logger logger = LoggerFactory.getLogger(AbstractRedisClient.class);
    protected static Pool<? extends JedisCommands> pool = null;

    public AbstractRedisClient(Pool<? extends JedisCommands> redisPool) {
        pool = redisPool;
    }

    protected abstract void setPool(Pool<? extends JedisCommands> arg0);

    protected <P> void run(IRedisClient.RedisTask<P> task) {
        Object jedis = getJedis();

        try {
            task.run((P)jedis);
        } catch (Exception arg6) {
            logger.error(arg6.getMessage(), arg6);
            throw new RedisException(arg6.getMessage(), arg6);
        } finally {
            this.close().run(jedis);
        }
    }

    protected <T, P> T run(IRedisClient.RedisResultTask<T, P> task) {
        Object jedis = getJedis();

        Object e;
        try {
            e = task.run((P) jedis);
        } catch (Exception arg6) {
            logger.error(arg6.getMessage(), arg6);
            throw new RedisException(arg6.getMessage(), arg6);
        } finally {
            this.close().run(jedis);
        }
        return (T) e;
    }

    protected abstract <T> IRedisClient.RedisTask<T> close();

    protected static <T> T getJedis() {
        int timeoutCount = 0;

        while (true) {
            try {
                JedisCommands e = (JedisCommands) pool.getResource();
                return (T) e;
            } catch (Exception arg1) {
                if (!(arg1 instanceof JedisConnectionException) && !(arg1 instanceof SocketTimeoutException)) {
                    logger.warn("jedisInfo:NumActive={}, NumIdle={}, NumWaiters={}, isClosed={}",
                            new Object[] { Integer.valueOf(pool.getNumActive()), Integer.valueOf(pool.getNumIdle()),
                                    Integer.valueOf(pool.getNumWaiters()), Boolean.valueOf(pool.isClosed()) });
                    logger.error("getJedis error", arg1);
                } else {
                    ++timeoutCount;
                    logger.warn("getJedis timeoutCount={}", Integer.valueOf(timeoutCount));
                    if (timeoutCount <= 3) {
                        continue;
                    }
                }

                return null;
            }
        }
    }

}
